package com.egg.common.feign.config;

import cn.hutool.core.util.ObjectUtil;
import com.egg.common.util.HttpServletUtil;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * feign 请求拦截器
 *
 * @author east
 */
@Slf4j
@Aspect
// 扫描降级 - 会导致服务无法启动
@ComponentScan(basePackages = "com.egg")
// 注入feign客户端 - 服务可以正常启动, feign客户端会为null
@EnableFeignClients(basePackages = "com.egg")
@Configuration
public class FeignRequestInterceptorConfig implements RequestInterceptor {


    @Bean
    public RequestInterceptor feignRequestInterceptor() {
        return new FeignRequestInterceptorConfig();
    }

    /**
     * 切点
     * execution 两个..代表所有子目录，最后括号里的两个..代表所有参数
     *
     * @annotation 所有注解的方法拦截
     * @target 只匹配标注了指定注解的类。不涉及任何其他类。
     * @within 会匹配到标注了指定注解的类，并且在该类的子类中，那些没有重写的父类方法也会被匹配到。
     */
    @Pointcut("@within(org.springframework.cloud.openfeign.FeignClient)")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = HttpServletUtil.getServletRequestAttributes();
        if (null == attributes) {
            return;
        }
        // 传递seata的xid
        attributes.getRequest().setAttribute(RootContext.KEY_XID, RootContext.getXID());
        RequestContextHolder.setRequestAttributes(attributes, true);
    }

    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        HttpServletRequest request = HttpServletUtil.getHttpServletRequest();
        if (null == request) {
            return;
        }
        try {
            Object xid = request.getAttribute(RootContext.KEY_XID);
            if (ObjectUtil.isNotEmpty(xid)) {
                try {
                    // 传递seata的xid
                    requestTemplate.header(RootContext.KEY_XID, xid.toString());
                } catch (Exception e) {

                }
            }
        } catch (Exception e) {
        }
        Enumeration<String> headerNames = request.getHeaderNames();
        if (null != headerNames) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String values = request.getHeader(name);
                if (name.equals("content-length")) {
                    continue;
                }
                try {
                    requestTemplate.header(name, values);
                } catch (Exception e) {

                }
            }
        }
    }


}